home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / games_d / oasys.zip / OASYS.DOC < prev   
Text File  |  1991-03-03  |  80KB  |  1,950 lines

  1. 1: Introduction
  2.       OASYS stands for Object-Oriented Adventure System. It is a system designed
  3.       for writing text adventure games. The "Object-Oriented" in the title means
  4.       that the system is built around the objects that appear in the game. This
  5.       means that you can write adventure games faster and more easily than with
  6.       older systems.
  7.  
  8.       The system and this manual are designed under the assumption that you know
  9.       the basics of how to use a computer but are not a programmer. From time to
  10.       time you will come across technical notes in the manual, enclosed in
  11.       square brackets [like this]. These contain extra information that you
  12.       don't need to know about to use the system, and you can completely ignore
  13.       them if you like.
  14.  
  15.       [OASYS contains a general-purpose object-oriented programming language
  16.       that could be used to write many different types of programs, however it's
  17.       mostly designed for adventure games.]
  18.  
  19. 2: Files
  20.       You should have the following files:
  21.  
  22.       OAC         The compiler program
  23.       OAD         The disassembler program
  24.       OAI         The interpreter program
  25.  
  26.       EXAMPLE.S   A simple example adventure game
  27.       ESCAPE.S    A full-length example adventure game
  28.  
  29.       OASYS.PRN   A version of this manual suitable for printing out
  30.       OASYS.DOC   A version of this manual suitable for reading on the screen.
  31.  
  32.       You may have the following files which are the source code for OASYS
  33.       itself. You don't need them to use OASYS but if you are a programmer you
  34.       can use them to find out how the system works and to modify it:
  35.  
  36.       INS.H
  37.       OAC.C
  38.       OAD.C
  39.       OAI.C
  40.       RWLIB.H
  41.       RW.LIB
  42.  
  43.       File names have been given in upper case here for clarity. On most
  44.       computers it doesn't matter whether you type file names in upper or lower
  45.       case. However if you are using a UNIX system, you must type all file names
  46.       in lower case.
  47.  
  48. 3: Usage
  49.       How do you create an adventure game with OASYS? There are two stages in
  50.       the process:
  51.  
  52.       First, you must write the game in the OASYS game description language.
  53.       This can be done with any text editor or word processor. However if you
  54.       are using a word processor, you must make sure that it can write files in
  55.       plain ASCII format - if in doubt, check the manual for your word
  56.       processor.
  57.  
  58.       Suppose you were writing a game called Zork (this is the name of one of
  59.       the most famous adventure games ever written). And suppose you are using
  60.       WordStar to write the game description. You would type:
  61.  
  62.       WS ZORK.S
  63.  
  64.       to create a file called ZORK.S. (OASYS expects the file name to end with
  65.       ".S"). This is called the "source file" or "source code" - hence the S for
  66.       "source" at the end of the file name.
  67.  
  68.       Second, you must translate the human-readable source code into "object
  69.       code" which can be run on the computer. This is done by typing:
  70.  
  71.       OAC ZORK.S
  72.  
  73.       or:
  74.  
  75.       OAC ZORK
  76.  
  77.       (note that it doesn't matter whether or not you type the ".S" at the end
  78.       of the source file name). This will cause the OAC program (the "compiler")
  79.       to translate the human-readable ZORK.S file into the machine-readable ZORK
  80.       file.
  81.  
  82.       Finally, to play the game you type:
  83.  
  84.       OAI ZORK
  85.  
  86.       This will cause the OAI program (the "interpreter") to read the ZORK file
  87.       and run the game. To give your adventure game to other people you must
  88.       give them the ZORK file and the OAI program. You may choose to give them
  89.       the ZORK.S file if you want them to see how your adventure is written. And
  90.       you may choose to give them the OAC file as well if you want them to be
  91.       able to change your adventure (by changing ZORK.S and typing OAC ZORK).
  92.  
  93.       So to summarize, there are two files and two programs involved:
  94.  
  95.       ZORK.S is the human-readable "source file" that you create with a word
  96.       processor.
  97.       ZORK is the machine-readable "object file" that can be played.
  98.       OAC is the program that translates the source file into the object file.
  99.       OAI is the program that runs the object file.
  100.  
  101.       Word Processor -> ZORK.S -> OAC -> ZORK -> OAI -> Player
  102.  
  103.       You can try all this out with the two example adventure games supplied
  104.       with OASYS. To translate and run EXAMPLE, type:
  105.  
  106.       OAC EXAMPLE
  107.       OAI EXAMPLE
  108.  
  109.       Similarly you can translate and run ESCAPE.
  110.  
  111.       What happens if you accidentally type OAI ZORK.S, in other words giving
  112.       OAI the human-readable source file instead of the machine-readable object
  113.       file? It won't do any harm because OAI knows what object files are
  114.       supposed to look like and will reject anything else with an error message.
  115.  
  116.       What about the "disassembler" program mentioned above? You don't actually
  117.       need it at all. It was written to help debug the other two programs, and
  118.       included in the package in case anyone was interested in it. What it does
  119.       is to let you examine the object file. You use it by typing:
  120.  
  121.       OAD ZORK
  122.  
  123.       It will generate a listing of the internal structure of the object file.
  124.       Note that this listing is not in any way a substitute for the original
  125.       source file. Also note that the listing is very long! If you want to try
  126.       out the program, try it out on EXAMPLE first. If you decide to try it on
  127.       ESCAPE, you can press CTRL-C to stop it.
  128.  
  129.       Of course, you will have to translate EXAMPLE.S and ESCAPE.S into EXAMPLE
  130.       and ESCAPE with the OAC program before you can try out OAD.
  131.  
  132.       [Actually you can give the source file any extension you like. However if
  133.       it's anything other than ".S" you must supply the extension when running
  134.       OAC.]
  135.  
  136. 4: Portability
  137.       Having read the rest of the manual you will know how to write an adventure
  138.       game with OASYS, and having read the previous section you will know how to
  139.       translate and run it. Now what happens when you want to port the game?
  140.       "Port" means "make work on a different type of computer". Suppose you've
  141.       written a game on a PC-compatible machine and you want it to run on a UNIX
  142.       system, you must do the following:
  143.  
  144.       First, get a version of OASYS for the UNIX system. You cannot port OASYS
  145.       itself unless you are a programmer, so if you can't get a version for UNIX
  146.       you'll have to forget about it for the moment.
  147.  
  148.       Now, copy the source file to the UNIX system. Don't try to copy the object
  149.       file! The format it's stored in varies for different types of computers,
  150.       so the UNIX version of OAI won't understand an object file created by the
  151.       PC version of OAC. However it will *think* it can understand it and will
  152.       try to run it, probably crashing the computer.
  153.  
  154.       Now, run the OAC program on the UNIX system to create a version of the
  155.       object file that'll work on UNIX. Then run it with OAI.
  156.  
  157.       Note that only one file - your source file - ever got copied from the PC
  158.       to the UNIX computer.
  159.  
  160.       [Actually it *may* be possible to copy the object file directly. It will
  161.       only work if source and destination machines have the same byte ordering
  162.       and the same int size.]
  163.  
  164.       [If you haven't got a version of OASYS for a target system, you're welcome
  165.       to try porting it yourself - it shouldn't be too hard provided you have a
  166.       C++ compiler for the target system.]
  167.  
  168. 5: Language
  169.       This section of the manual contains information on how to write your
  170.       source code. It is suggested that you print out EXAMPLE.S and ESCAPE.S and
  171.       refer to them as you read this section of the manual, since a few examples
  172.       are usually better than any amount of explanation. Also you may need to
  173.       scan through the manual several times before you understand all of it.
  174.  
  175. 5.1:  Case
  176.      All examples have been given in upper case for clarity. However it
  177.      doesn't matter whether you type your code in upper or lower case.
  178.      (Unlike filenames, this is true even on UNIX systems). I personally
  179.      prefer lower case and EXAMPLE.S and ESCAPE.S are all in lower case.
  180.  
  181. 5.2:  Spaces
  182.      OASYS regards any amount of "whitespace" characters (space, tab or new
  183.      line) as being the same as a single space. This means that whenever you
  184.      see two words or symbols separated by a space in the example code, you
  185.      could put in any number of spaces or even put them on separate lines.
  186.      Conversely, if you see two things on separate lines, you could put them
  187.      on the same line separated by a space. For the sake of clarity it is
  188.      the convention to put no more than one definition, statement etc. on a
  189.      line but you need not stick to this.
  190.  
  191. 5.3:  Identifiers
  192.      The names of all kinds of things (e.g. object classes, methods etc.)
  193.      must be one word "identifiers". An identifier is a sequence of letters
  194.      and digits but it must begin with a letter. So
  195.  
  196.      ROOM
  197.      SATURN5
  198.      HYDROGENBOMB
  199.  
  200.      are valid identifiers, but
  201.  
  202.      9TO5
  203.  
  204.      is not (OASYS will look at the 9 at the front and think it's a number,
  205.      then get confused when it sees the TO).
  206.  
  207.      So you can't use more than one word for an identifier - but the
  208.      underscore character "_" is actually counted by OASYS as a letter! So
  209.      the above could be written as
  210.  
  211.      ROOM
  212.      SATURN_5
  213.      HYDROGEN_BOMB
  214.      _9_TO_5
  215.  
  216.      Note that the last is now legal! And the use of "_" makes the names
  217.      more readable. However remember that "_" is NOT the same as the hyphen
  218.      "-".
  219.  
  220. 5.4:  Comments
  221.      Comments may be inserted anywhere at all in your source code. These are
  222.      "marginal notes" to explain how something works, for the benefit of
  223.      other people who want to read your code or for your own benefit if you
  224.      come back in six months time. There are two ways to define comments:
  225.  
  226.      Anything from the symbol // to the end of the line is a comment e.g.
  227.  
  228.      ... // This is a comment
  229.  
  230.      Anything between the symbols /* and */ is a comment e.g.
  231.  
  232.      /* This is
  233.         another comment */
  234.  
  235.      The // comments are better for one-line notes whereas the /*...*/
  236.      comments are better for multi-line explanations.
  237.  
  238.      Another use for comments is "commenting out" code. Suppose you have a
  239.      chunk of code you want to remove but you might want to put it back in
  240.      again later. You don't want to actually delete it because then if you
  241.      do want to put it back in you'll have a lot of unncessary typing to do.
  242.      So you enclose it it comment symbols - then OASYS will ignore it but
  243.      you can put it back in anytime just by deleting the comment symbols.
  244.      Either put // at the beginning of each line or put /* at the beginning
  245.      of the code and */ at the end.
  246.  
  247.      When commenting out code, remember that you can't nest /*...*/ comments
  248.      e.g. suppose you have commented out a method definition as follows:
  249.  
  250.      /*
  251.      METHOD SOMETHING
  252.      {
  253.          ...
  254.          /* This is a comment
  255.         inside the method definition */
  256.          ...
  257.      }
  258.      */
  259.  
  260.      OASYS will think the first */ inside the method definition corresponds
  261.      to the /* before the method definition. So it will only see the second
  262.      half of the method definition, and an apparently unmatched */ symbol!
  263.      Where you have /*...*/ comments inside something you want to comment
  264.      out, you should do the commenting out with // symbols.
  265.  
  266. 5.5:  Order of definitions
  267.      When writing the various sections of your source code, remember that
  268.      OAC only scans through the source file *once* for the sake of speed.
  269.      This means that everything defined in one part of the source code and
  270.      referred to in another part must be defined *before* it is referred to.
  271.  
  272. 5.6:  Objects
  273.      OASYS is based on objects. Unlike other systems, even locations and the
  274.      player are objects. When a game is starting, no objects exist. You must
  275.      arrange for some objects (such as the player and locations!) to be
  276.      created at the start. Later more objects may be created and old ones
  277.      destroyed. Every object belongs to a class, so the first thing to do is
  278.      usually to define what classes you are going to have. (Remember
  279.      everything must be defined before it's referred to and you're going to
  280.      refer to your classes a lot!) For example:
  281.  
  282.      CLASS PLAYER {{ME} {SELF} {MYSELF}}
  283.      CLASS ROOM {}
  284.      CLASS MACHINE_GUN {{GUN} {MACHINE GUN}}
  285.  
  286.      The first of these is the class to which the player object is going to
  287.      belong. The things after the word PLAYER mean that the (human) player
  288.      may refer to himself with the words ME, SELF or MYSELF e.g. EXAMINE
  289.      MYSELF or KILL SELF. The empty pair of curly brackets after the word
  290.      ROOM means that the player cannot refer to objects of class ROOM. The
  291.      definition of CLASS MACHINE_GUN says that the player can refer to
  292.      objects of this class with the word GUN or the phrase MACHINE GUN, so
  293.      GET GUN or GET MACHINE GUN will mean the same thing.
  294.  
  295.      In general, a class definition consists of the word CLASS followed by
  296.      the class name, an open curly bracket "{", a list of phrases which can
  297.      be used to refer to objects of that class, and a close curly bracket
  298.      "}". Each phrase is an open curly bracket, a list of words and a close
  299.      curly bracket. The reason you need the curly brackets around the list
  300.      of words is to tell OASYS when the list of words is finished, and the
  301.      reason you need the curly brackets around the list of phrases is to
  302.      tell OASYS when the list of phrases is finished.
  303.  
  304.      Note that unlike many systems, OASYS lets you have many objects
  305.      belonging to the same class, so you can have say several identical
  306.      MACHINE_GUNs. Of course all your locations will be objects of class
  307.      ROOM. (Unless you decide for some reason to have some locations of say
  308.      class TUNNEL or TREETOP or whatever).
  309.  
  310. 5.7:  Properties
  311.      As well as belonging to classes objects have properties, such as
  312.      description and weight. Unlike other systems OASYS starts with no
  313.      preconceived idea of what properties objects are going to have. You
  314.      must define the list of properties. When you have done this each object
  315.      in your game will possess different values for these properties, for
  316.      example:
  317.  
  318.      PROPERTY INT WEIGHT
  319.      PROPERTY STRING DESCRIPTION
  320.      PROPERTY OBJECT IN
  321.  
  322.      As you can see, each property in the list starts with the word
  323.      PROPERTY. Then is the property type, which can be INT, STRING or
  324.      OBJECT. Last comes the name of the property.
  325.  
  326.      INT properties are a number, in this example WEIGHT. These properties
  327.      are called INT because the number must be an integer i.e. a whole
  328.      number. (Numbers with decimals may be allowed in a future version of
  329.      OASYS).
  330.  
  331.      STRING properties are a piece of text. The name STRING comes from the
  332.      fact that each is a "string" of letters, digits, punctuation marks or
  333.      whatever.
  334.  
  335.      OBJECT properties are a reference to another object.
  336.  
  337.      So how would the above be used? All objects of class MACHINE_GUN might
  338.      be assigned a WEIGHT of 15 when created; objects of other classes might
  339.      be assigned different WEIGHTs. (Of course you could also assign
  340.      different WEIGHTs to different MACHINE_GUNs).
  341.  
  342.      WEIGHT is not useful for objects of class ROOM. All objects will have a
  343.      WEIGHT of 0 when created, so you would not bother to change this for
  344.      ROOMs.
  345.  
  346.      DESCRIPTION would be used for almost all types of objects. (An
  347.      exception might be the player). For example, one ROOM might have a
  348.      DESCRIPTION of "Long dark tunnel" whereas another ROOM might have a
  349.      DESCRIPTION of "Large hall". All MACHINE_GUNs might have a DESCRIPTION
  350.      of "A machine gun".
  351.  
  352.      All STRING properties have an initial value of "*NULL STRING*" so that
  353.      if you forget to assign the proper value to one you will notice quickly
  354.      when testing the game.
  355.  
  356.      IN in this example is used to indicate what other object this object is
  357.      contained in. For example, the player's IN value might indicate which
  358.      ROOM he is in. An object's IN value might refer to a ROOM object. Or it
  359.      might refer to the player object to mean that the object was being
  360.      carried by the player.
  361.  
  362.      All OBJECT properties start off with a value of OBJECT 0 which means no
  363.      object at all. (The exact meaning of the expression OBJECT 0 is
  364.      explained in the "Expressions" section of the manual). You would leave
  365.      a ROOM's IN property as OBJECT 0 because ROOMs are not IN anything.
  366.  
  367. 5.8:  Methods
  368.      Methods are how everything gets done in OASYS. For example:
  369.  
  370.      METHOD INT SQUARE INT X
  371.      {
  372.          RETURN X * X
  373.      }
  374.  
  375.      is a method which will calculate the square of a number. The definition
  376.      consists of:
  377.  
  378.      the word METHOD
  379.  
  380.      the name of the method, SQUARE
  381.  
  382.      the word INT to indicate that it returns an INT value. (Types that
  383.      methods can return are INT, STRING and OBJECT, the same as for
  384.      properties).
  385.  
  386.      one "argument" passed to the method. This method is called X and is of
  387.      type INT. (Types for method arguments are INT, STRING and OBJECT).
  388.  
  389.      an open curly bracket to indicate the start of the actual method code.
  390.  
  391.      the method code, in this case just one line to cause the square of the
  392.      argument X to be returned.
  393.  
  394.      a close curly bracket to indicate the end of the method definition.
  395.  
  396.      Now here is another method:
  397.  
  398.      METHOD LOOK VERBS {{LOOK} {DESCRIBE LOCATION}}
  399.      {
  400.          PRINT PLAYER IN DESCRIPTION
  401.      }
  402.  
  403.      This consists of:
  404.  
  405.      the word METHOD
  406.  
  407.      *no* type name for the method - this is because this method does not
  408.      return anything at all.
  409.  
  410.      the name of the method, LOOK
  411.  
  412.      the word VERBS
  413.  
  414.      a list of phrases which the player can type to call this method - this
  415.      is the same as the list of nouns for a CLASS.
  416.  
  417.      the method code as above - this time the method code prints the
  418.      description of the ROOM the player is IN, but does not RETURN anything.
  419.  
  420.      So some methods are actually verbs. Whenever the (human) player types a
  421.      command, OASYS searches for a method with a corresponding verb. If
  422.      found, the method is called. The method SQUARE had no VERBS and so was
  423.      purely for internal use.
  424.  
  425.      A method with VERBS can't have any STRING arguments. (This limitation
  426.      may be removed in future versions). It can have INT arguments, but the
  427.      player is not allowed to type negative numbers. (This limitation may
  428.      also be removed in future versions). However if the method is also
  429.      called by other methods, the other methods can supply negative numbers
  430.      for the INT arguments even though the player can't.
  431.  
  432.      Suppose you want a method with both verbs and arguments? You can
  433.      specify the position of the arguments in the verbs e.g.
  434.  
  435.      METHOD GIVE_TO OBJECT X IS_CARRIED OBJECT Y IS_VISIBLE
  436.          VERBS {{GIVE X TO Y} {OFFER X TO Y} {GIVE Y X} {OFFER Y X}}
  437.      {
  438.          ...
  439.      }
  440.  
  441.      What this means is that if the player wants to give something to
  442.      something else he must type the "give" command with the names of the
  443.      two objects. The first object, which is being given, must be carried by
  444.      the player. The second object, which is being given the first object,
  445.      must be visible. (For further explanation of IS_CARRIED and IS_VISIBLE,
  446.      see below). The alternative ways the player can phrase the command are
  447.      given in the VERBS definition. There is an example in ESCAPE.S where
  448.      the player must give a fish to a tiger, and the alternative ways this
  449.      could be phrased are:
  450.  
  451.      GIVE FISH TO TIGER
  452.      OFFER FISH TO TIGER
  453.      GIVE THE TIGER THE FISH
  454.      OFFER THE TIGER THE FISH
  455.  
  456.      The word THE, inserted above for clarity, is always ignored when the
  457.      player types in a command so that is why it is not present in the VERBS
  458.      definition. You can use more informative names than X and Y for the
  459.      method arguments but whatever names you use must be correctly placed in
  460.      the VERBS definition e.g.
  461.  
  462.      METHOD GIVE_TO OBJECT GIFT IS_CARRIED OBJECT RECIPIENT IS_VISIBLE
  463.          VERBS {{GIVE GIFT TO RECIPIENT} {OFFER GIFT TO RECIPIENT}
  464.             {GIVE RECIPIENT GIFT} {OFFER RECIPIENT GIFT}}
  465.      {
  466.          ...
  467.      }
  468.  
  469.      would also work.
  470.  
  471. 5.9:  Variables
  472.      As well as properties you can have "global variables" which are like
  473.      properties but there's only one of them. For example,
  474.  
  475.      INT SCORE
  476.  
  477.      could record the current score in the game. You only want this recorded
  478.      once not for every object, so you make it a global variable rather than
  479.      a property. This is done by only having the type (INT, STRING or
  480.      OBJECT) and the name, without the word PROPERTY.
  481.  
  482.      Also you can have what are called "local variables" within methods. You
  483.      define them exactly like global variables, but put the definition
  484.      *inside* the method definition, just before the method code. e.g.
  485.      METHOD SQUARE could be rewritten:
  486.  
  487.      METHOD INT SQUARE INT X
  488.      {
  489.          INT RESULT
  490.  
  491.          RESULT = X * X
  492.          RETURN RESULT
  493.      }
  494.  
  495.      The variable RESULT only exists within METHOD SQUARE. You could define
  496.      STRING RESULT in another method elsewhere in the source code and there
  497.      would be no conflict.
  498.  
  499.      Note that it is the convention to separate the variable definition(s)
  500.      from the method code with one blank line (but this is not required).
  501.  
  502.      Why use local variables at all when global variables will do the same
  503.      job? Well, if you only want to use a variable within one method, making
  504.      it a local variable makes it a lot easier to keep track of what you're
  505.      doing because if you forget where you used it you have a lot less code
  506.      to search through. Also they're essential for "recursion" (q.v.).
  507.  
  508.      You can't have two global variables with the same name, or two local
  509.      variables with the same name within the same method. What if you have a
  510.      global variable, and within a method a local variable with the same
  511.      name? e.g. suppose in the above example there was a global variable
  512.      OBJECT RESULT already defined? No problem. Within METHOD SQUARE, RESULT
  513.      would be taken to mean the local INT RESULT. Within other methods,
  514.      RESULT would be taken to mean the global OBJECT RESULT.
  515.  
  516.      Arguments to methods have the same status as local variables. For
  517.      example, in METHOD SQUARE it would not have been legal to have a local
  518.      variable STRING X because it would conflict with the argument INT X.
  519.  
  520. 5.10: THIS
  521.      All methods are considered to be "applied to" an object, for example
  522.      methods that correspond to typed commands are considered to be applied
  523.      to the PLAYER object. The way this works is that all methods have an
  524.      implicit argument OBJECT THIS which is whatever the method is applied
  525.      to.
  526.  
  527.      So suppose you have a METHOD GET which is called when the player wants
  528.      to GET an object. THIS will then be the player object. On the other
  529.      hand if the player tells something else to GET something (see below for
  530.      how to do this), THIS will be that something else. So you can write the
  531.      method to distinguish between when THIS is the player (in which case
  532.      the command will be carried out) and when THIS is not the player (in
  533.      which case there may be a refusal to carry out the command!). For
  534.      another example of the use of THIS, see "selector methods".
  535.  
  536.      On the other hand for methods like SQUARE above which give the same
  537.      result no matter what object they're applied to, THIS won't be used at
  538.      all, although it must still be supplied.
  539.  
  540.      Whenever a method is called applied to OBJECT 0, it will return
  541.      immediately without executing any of the method code. The return value
  542.      if any will be set to 0 for an INT method, "*NULL STRING*" for a STRING
  543.      method or OBJECT 0 for an OBJECT method.
  544.  
  545. 5.11: METHOD INIT
  546.      Methods with verbs are called when the player types commands, and this
  547.      is how things get done. However when the game starts some objects need
  548.      to be created initially and other setting up may also need to be done.
  549.      The way this is done is, you must have a method defined as follows:
  550.  
  551.      METHOD INIT
  552.      {
  553.          ...
  554.      }
  555.  
  556.      i.e. it must not return a value or have arguments or verbs (though it
  557.      may have local variables). This method will get called at the start of
  558.      every game.
  559.  
  560. 5.12: Selector methods
  561.      Consider this definition (used in the section on "Methods"):
  562.  
  563.      METHOD GIVE_TO OBJECT X IS_CARRIED OBJECT Y IS_VISIBLE
  564.          VERBS {{GIVE X TO Y} {OFFER X TO Y} {GIVE Y X} {OFFER Y X}}
  565.      {
  566.          ...
  567.      }
  568.  
  569.      The IS_CARRIED and IS_VISIBLE are called "selector methods". The point
  570.      is, suppose you have many MACHINE_GUNs in the game and the player types
  571.      GIVE MACHINE GUN TO GUARD, and the player is only carrying one machine
  572.      gun, obviously you want your GIVE_TO method to be called with the
  573.      correct machine gun, otherwise the GIVE_TO method will only see that
  574.      the player does not have X, it will not see that there is another
  575.      machine gun that he does have, so it will idiotically respond that the
  576.      player does not have the machine gun.
  577.  
  578.      Also in traditional adventure writing systems, the writer has to waste
  579.      a great deal of time checking, for each and every possible command,
  580.      that the player has or can see the objects referred to. So you want the
  581.      checking to be done *before* your GIVE_TO or whatever method is called.
  582.  
  583.      Selector methods are the answer to this. The above tells OASYS, "for
  584.      argument X, call method IS_CARRIED to check whether it's valid; for
  585.      argument Y, call method IS_VISIBLE to check whether it's valid". This
  586.      will produce the desired result if you have previously defined
  587.      something like:
  588.  
  589.      METHOD INT IS_CARRIED
  590.      "You haven't got that.\n"
  591.      {
  592.          RETURN THIS IN == PLAYER
  593.      }
  594.  
  595.      METHOD INT IS_VISIBLE
  596.      "That isn't here.\n"
  597.      {
  598.          RETURN THIS IS_CARRIED OR THIS IN == PLAYER IN
  599.      }
  600.  
  601.      Of course you can have as many selector methods as you like and call
  602.      them whatever you like but the above two are widely useful.
  603.  
  604.      More complicated versions of IS_CARRIED and IS_VISIBLE are defined in
  605.      ESCAPE.S to cope with the possibility that for example, something might
  606.      still be visible if it was in an object that itself was in the player's
  607.      location.
  608.  
  609.      Selector methods take no arguments. THIS represents the object which is
  610.      being tested. The selector method must return an INT value, which is
  611.      zero if THIS is not valid and non-zero if THIS is valid.
  612.  
  613.      The two messages just before the open curly brackets for the two
  614.      methods are the messages that will be displayed if the object is found
  615.      not to be carried or visible respectively. (Such messages should only
  616.      be defined for selector methods, not for other methods).
  617.  
  618.      Why can the message not simply be displayed by the selector method
  619.      itself if THIS is found to be invalid, instead of having to be
  620.      specially defined for OASYS to display? Because suppose the player
  621.      types GIVE MACHINE GUN TO GUARD and you have many machine guns in the
  622.      game, none of which is in the player's possession. Each and every one
  623.      of them will be checked for IS_CARRIED but you only want one "You
  624.      haven't got that" message to be displayed.
  625.  
  626.      Of course if you know that you only have one object of each class in
  627.      your game, you can have the message printed by the selector method
  628.      instead of defining it before the open curly bracket (say if you want
  629.      to give a more specific message like "You haven't got the machine
  630.      gun.").
  631.  
  632. 5.13: METHOD SELECT_ADDRESSEE
  633.      The player can talk to other objects in the game! The command for this
  634.      is for example "GUARD, DROP MACHINE GUN" will give the command to drop
  635.      the machine gun to the guard as typing "DROP MACHINE GUN" would give
  636.      the command to drop the machine gun to the player object. Of course you
  637.      would probably have programmed your METHOD DROP to check if the DROP
  638.      command was being given to something other than the player, and if so
  639.      not necessarily carry out the order!
  640.  
  641.      In general, to give a command to another object, the player must type
  642.      the name of the object to be addressed, followed by a comma and then
  643.      the rest of the command.
  644.  
  645.      The problem arises again here of how to select which objects the player
  646.      can talk to, just as it did earlier of how to select which objects a
  647.      command can apply to. For example, if you have many guards in the game
  648.      you want to make sure the one the player ends up talking to is the one
  649.      in the same location as the player.
  650.  
  651.      There is a special selector method for things the player can talk to.
  652.      It's called METHOD SELECT_ADDRESSEE. If you have this defined it will
  653.      be used, if you haven't got it defined the player will just get the
  654.      message "You can't talk to that" whenever he tries to talk to anything.
  655.      An example is:
  656.  
  657.      METHOD SELECT_ADDRESSEE
  658.      "It doesn't understand you!\n"
  659.      {
  660.          RETURN (THIS IS GUARD OR THIS IS ROBOT) AND THIS IS_VISIBLE
  661.      }
  662.  
  663.      which will only let you talk to GUARDs or ROBOTs which are visible. (Of
  664.      course, you must have previously defined the selector method
  665.      IS_VISIBLE).
  666.  
  667.      If you don't have the message defined for METHOD SELECT_ADDRESSEE it
  668.      will default to "You can't talk to that".
  669.  
  670. 5.14: Player
  671.      The player is represented by an object. There is a predefined global
  672.      variable OBJECT PLAYER which tells OASYS which is the player object.
  673.      Suppose you have defined
  674.  
  675.      CLASS PLAYER {{ME} {SELF} {MYSELF}}
  676.  
  677.      (which will let the player type commands like EXAMINE SELF and KILL
  678.      MYSELF), you must put into METHOD INIT something along the lines of:
  679.  
  680.      PLAYER = CREATE PLAYER
  681.  
  682.      Of course, you don't have to have a CLASS PLAYER defined; if you don't
  683.      want the player to be able to type commands that refer to himself and
  684.      you have already defined
  685.  
  686.      CLASS ROOM {}
  687.  
  688.      for locations, you could have
  689.  
  690.      PLAYER = CREATE ROOM
  691.  
  692.      in METHOD INIT, and it would work perfectly well.
  693.  
  694.      This means that you can have a facility in your game whereby the player
  695.      can take on the identity of many different characters at different
  696.      times. For example in the game "Lord of the Rings" on the Commodore 64,
  697.      the four hobbits Frodo, Sam, Merry and Pippin appeared as characters
  698.      and the player could play any of them with the BECOME command.
  699.      Supposing the player started off playing FRODO, he could type BECOME
  700.      SAM. This could be implemented in OASYS like this:
  701.  
  702.      CLASS FRODO {{FRODO}}
  703.      CLASS SAM {{SAM}}
  704.      CLASS MERRY {{MERRY}}
  705.      CLASS PIPPIN {{PIPPIN}}
  706.  
  707.      ...
  708.  
  709.      OBJECT FRODO
  710.      OBJECT SAM
  711.      OBJECT MERRY
  712.      OBJECT PIPPIN
  713.  
  714.      ...
  715.  
  716.      METHOD INT IS_BECOMABLE
  717.      {
  718.          RETURN THIS SELECT_ADDRESSEE AND (THIS IS FRODO OR
  719.                            THIS IS SAM OR
  720.                            THIS IS MERRY OR
  721.                            THIS IS PIPPIN)
  722.      }
  723.  
  724.      METHOD BECOME OBJECT X IS_BECOMABLE VERBS {{BECOME X}}
  725.      {
  726.          PLAYER = X
  727.      }
  728.  
  729.      METHOD INIT
  730.      {
  731.          ...
  732.          FRODO = CREATE FRODO
  733.          SAM = CREATE SAM
  734.          MERRY = CREATE MERRY
  735.          PIPPIN = CREATE PIPPIN
  736.  
  737.          PLAYER = FRODO      // Player starts off playing Frodo
  738.          ...
  739.      }
  740.  
  741.      Note that if you have already defined METHOD SELECT_ADDRESSEE you can
  742.      use it to help select which objects are becomable. The above example
  743.      assumes that there are some characters in the game which the players
  744.      can talk to but not become.
  745.  
  746.      Also you must have different CLASSes for each of the four hobbits
  747.      rather than for example just a CLASS HOBBIT because the player has to
  748.      be able to distinguish between the four when typing commands.
  749.  
  750. 5.15: Parser
  751.      The "parser" is that part of the OAI program which accepts typed input
  752.      from the player and calls methods accordingly.
  753.  
  754. 5.15.1:  Features
  755.         The player may talk to other objects by prefacing the command with
  756.         the name of the other object and a comma.
  757.  
  758.         The word THE is ignored, so TAKE MACHINE GUN is the same as TAKE THE
  759.         MACHINE GUN (and for that matter the same as THE THE TAKE THE
  760.         MACHINE THE GUN).
  761.  
  762.         Verbs and nouns may have multiple words e.g. PICK UP THE MACHINE GUN
  763.         is as easy to implement as TAKE THE AXE. However each alternative
  764.         form of the noun must be defined in the CLASS definition and each
  765.         alternative form of the verb must be defined in the METHOD
  766.         definition.
  767.  
  768.         Words in the verb may be interspersed with nouns e.g. PICK THE
  769.         MACHINE GUN UP as well as PICK UP THE MACHINE GUN can be
  770.         implemented. Again this must be specified in the METHOD definition
  771.         with something like VERBS {{GET X} {TAKE X} {PICK UP X} {PICK X
  772.         UP}}.
  773.  
  774.         The player may type commands in upper case, lower case or a mixture
  775.         of both, it doesn't matter which.
  776.  
  777. 5.15.2:  Process
  778.         The process of interpreting a command works as follows:
  779.  
  780.         Each word is checked to make sure it appears somewhere in a CLASS or
  781.         METHOD definition. If a completely unrecognized word is found, the
  782.         player will receive the message "I don't understand the word 'xxx'."
  783.         where xxx is the offending word. Due to a quirk of the OAC program
  784.         design, the names of method arguments are regarded as valid words
  785.         even if they are not included in any verb or noun definitions. (This
  786.         may not be true in later versions of OASYS). So incorrect use of
  787.         such names will give the player the message "I don't understand
  788.         you." rather than the more specific message above.
  789.  
  790.         If there is a comma, the noun before the comma is compared with the
  791.         nouns given in CLASS definitions to decide what CLASS the addressee
  792.         belongs to. If no such class can be found, the player receives the
  793.         message "I don't know who you're trying to talk to." If METHOD
  794.         SELECT_ADDRESSEE is not defined, the player receives the message
  795.         "You can't talk to that.". Otherwise METHOD SELECT_ADDRESSEE is used
  796.         to find which actual object of that class is being addressed. If no
  797.         such object can be found, the player receives the message defined in
  798.         METHOD SELECT_ADDRESSEE, or "You can't talk to that." if there is no
  799.         such message defined.
  800.  
  801.         The command as a whole is compared with the verbs for the various
  802.         methods to decide which method is involved. If no method can be
  803.         found with a corresponding verb, the player will receive the message
  804.         "I don't understand you.".
  805.  
  806.         Each noun is compared with the nouns given in CLASS definitions to
  807.         decide which CLASS the noun refers to. Then the selector methods are
  808.         used to decide which actual object is being referred to for each
  809.         noun. If no object can be found, the player receives the message
  810.         defined in the selector method, if any. In either case the player
  811.         must type another command.
  812.  
  813.         The method with the corresponding verb is called with the
  814.         appropriate arguments. THIS is set to PLAYER if the command was
  815.         typed by itself, or the appropriate object if the command had an
  816.         addressee.
  817.  
  818. 5.15.3:  Omissions
  819.         The following features which are found in the parsers in some other
  820.         systems are not included in the OASYS parser, although they may be
  821.         included in future versions:
  822.  
  823.         The player must type only one command at a time, he cannot type
  824.         several commands separated by the word THEN.
  825.  
  826.         The word IT cannot be used to refer to a noun in the previous
  827.         command.
  828.  
  829.         The player cannot refer to many objects at once with the words AND
  830.         or ALL.
  831.  
  832.         Adjectives as distinct from nouns cannot be used e.g. if you have a
  833.         PLASTIC KEY, a METAL KEY and a CERAMIC key you must define the nouns
  834.         as PLASTIC KEY, METAL KEY and CERAMIC KEY and the player must type
  835.         the noun in full. He cannot just type KEY in the hope that it will
  836.         be obvious which key is being referred to.
  837.  
  838. 5.16: Code for methods
  839. 5.16.1:  Statements
  840.         The code for a method consists of a sequence of statements. A
  841.         statement may be one of the following:
  842.  
  843. 5.16.1.1:   { statements }
  844.            A sequence of zero or more statements surrounded by curly
  845.            brackets is equivalent to a single statement. This is used for
  846.            IF, WHILE and DO...WHILE constructs - if you want more than a
  847.            single statement in one of these you must surround them with
  848.            curly brackets. The conventional layout for writing statements
  849.            inside curly brackets is:
  850.  
  851.            {
  852.            statement 1
  853.            statement 2
  854.            ...
  855.            }
  856.  
  857.            i.e. put the "{" and "}" on separate lines and indent the
  858.            statements inside by one tab space.
  859.  
  860. 5.16.1.2:   PRINT expression
  861.            The word PRINT followed by an expression will display the
  862.            expression on the screen. The expression may be an integer or
  863.            string value. The print routine automatically arranges text for
  864.            output so that words are not broken up at the ends of lines. It
  865.            doesn't output anything until it has collected a whole word e.g.
  866.  
  867.            PRINT "F"
  868.            PRINT "R"
  869.            PRINT "E"
  870.            PRINT "D "
  871.  
  872.            will cause the word FRED to appear on the screen, but nothing
  873.            will actually appear until the last PRINT statement with the
  874.            space at the end is reached. A space or a new line character "\n"
  875.            will cause the collected output to be displayed.
  876.  
  877. 5.16.1.3:   RETURN
  878.            In methods which don't return a value, the word RETURN by itself
  879.            will cause execution of the method to finish. It's normally used
  880.            only with an IF statement because a return will happen
  881.            automatically if execution reaches the end of the method so you
  882.            don't need to use the word RETURN.
  883.  
  884. 5.16.1.4:   RETURN expression
  885.            In methods which do return a value, the word RETURN must be
  886.            followed by an expression of the appropriate type. The value of
  887.            the expression will be returned. If execution reaches the end of
  888.            the method without encountering a RETURN statement, a default
  889.            value will be returned following the same rules as for initial
  890.            values of variables i.e. INT methods will return 0, STRING
  891.            methods will return "*NULL STRING*" and OBJECT methods will
  892.            return OBJECT 0.
  893.  
  894. 5.16.1.5:   DESTROY expression
  895.            This will destroy the object given by the expression. If the
  896.            value of the expression is OBJECT 0 then OAI will stop with an
  897.            error message.
  898.  
  899.            When an object is destroyed, OASYS will look at all global
  900.            variables and object properties. Any which have OBJECT type and
  901.            refer to the destroyed object will be set to object 0. This does
  902.            *not* apply to local variables.
  903.  
  904.            So suppose you have a global variable OBJECT DYNAMITE which
  905.            refers to some dynamite. When the dynamite gets used up, you will
  906.            want to destroy the dynamite object to save memory, and also to
  907.            set the global variable DYNAMITE to OBJECT 0 to record the fact
  908.            that the dynamite isn't there anymore. You would expect to have
  909.            to do:
  910.  
  911.            DESTROY DYNAMITE
  912.            DYNAMITE = OBJECT 0
  913.  
  914.            but the second part is done automatically by OASYS so you just
  915.            need:
  916.  
  917.            DESTROY DYNAMITE
  918.  
  919.            [There is an exact correspondence between OASYS and C as follows:
  920.  
  921.            OBJECT          Pointer
  922.            CREATE (q.v.)   malloc()
  923.            DESTROY         free()
  924.            OBJECT 0        Null pointer
  925.  
  926.            *except* for the additional behaviour of DESTROY mentioned
  927.            above.]
  928.  
  929. 5.16.1.6:   EXIT
  930.            The EXIT statement will cause the game to end immediately. The
  931.            player will be asked if he wants to play again and if he does, a
  932.            new game will start.
  933.  
  934. 5.16.1.7:   QUIT
  935.            The QUIT statement will cause an "Are you sure? (Y/N)" message to
  936.            be displayed on the screen and the player will have to type Y, in
  937.            which case the game will stop as for the EXIT statement, or N, in
  938.            which case the game will continue as if nothing had happened.
  939.            QUIT should be used when the player has typed a QUIT command,
  940.            whereas EXIT should be used when the player has been killed or
  941.            for some other reason the player has no choice about the game
  942.            being over.
  943.  
  944. 5.16.1.8:   SAVE
  945.            The SAVE statement will cause the current state of the game -
  946.            global variables and the list of objects - to be saved to disk.
  947.            (The player will be prompted for a file name). After the save has
  948.            been done the game will continue as normal.
  949.  
  950. 5.16.1.9:   expression = expression
  951.            The expression on the left hand side of the = sign must be the
  952.            name of a global variable, local variable, method argument or a
  953.            property of some object. The expression on the right hand side
  954.            may be any expression of the same type as the one on the left
  955.            hand side. The variable or whatever on the left hand side will be
  956.            assigned the value on the right hand side as its new value, e.g.
  957.  
  958.            INT FRED
  959.  
  960.            FRED = 5
  961.  
  962. 5.16.1.10:  IF expression statement [ELSE statement]
  963.            The expression must be of type INT. The statement will be
  964.            executed if and only if the expression has a nonzero value. The
  965.            ELSE part, if present, will be executed if and only if the
  966.            expression has a zero value e.g.
  967.  
  968.            INT FLAG
  969.  
  970.            ...
  971.  
  972.            FLAG = 0
  973.  
  974.            ...
  975.  
  976.            IF FLAG PRINT "NOT ZERO\n" ELSE PRINT "ZERO\n"
  977.  
  978.            will cause ZERO to be printed.
  979.  
  980. 5.16.1.11:  WHILE expression statement
  981.            The expression must be of type INT. The statement will be
  982.            executed repeatedly as long as the expression has a nonzero value
  983.            e.g.
  984.  
  985.            INT X
  986.  
  987.            X = 5
  988.            WHILE X
  989.            {
  990.            PRINT "X = "
  991.            PRINT X
  992.            PRINT "\n"
  993.            X = X - 1
  994.            }
  995.  
  996.            will give the output:
  997.  
  998.            X = 5
  999.            X = 4
  1000.            X = 3
  1001.            X = 2
  1002.            X = 1
  1003.  
  1004.            Care must be taken to ensure that the loop will eventually
  1005.            terminate. For example, if the statement X = X - 1 had been
  1006.            omitted in the above example, the code would have kept printing X
  1007.            = 5 forever. OAI has no way to detect such a condition so the
  1008.            player would have to stop the program by pressing CTRL-C.
  1009.  
  1010. 5.16.1.12:  DO statement WHILE expression
  1011.            The DO...WHILE loop is like a WHILE loop except that the
  1012.            statement is executed before the expression is tested, so it is
  1013.            always executed once regardless of the value of the expression.
  1014.  
  1015. 5.16.1.13:  BREAK
  1016.            A BREAK statement will jump out of the enclosing WHILE or
  1017.            DO...WHILE loop. If the BREAK statement is not in a loop, an
  1018.            error message will be given.
  1019.  
  1020. 5.16.1.14:  CONTINUE
  1021.            A CONTINUE statement will jump to just before the end of the
  1022.            enclosing WHILE or DO...WHILE loop. If the CONTINUE statement is
  1023.            not in a loop, an error message will be given.
  1024.  
  1025. 5.16.1.15:  expression method_name arguments
  1026.            A call to a method which does not return a value is a statement.
  1027.            The expression must be of type OBJECT, and gives the object to
  1028.            which the method will be applied. This is followed by the name of
  1029.            the method and then by a list of expressions, one for each of the
  1030.            method's arguments if any, e.g.
  1031.  
  1032.            PLAYER IN DESCRIBE "You are in "
  1033.  
  1034.            assuming a previous definition of:
  1035.  
  1036.            METHOD DESCRIBE STRING MSG
  1037.            {
  1038.            PRINT MSG
  1039.            PRINT THIS DESCRIPTION
  1040.            PRINT ".\n"
  1041.            }
  1042.  
  1043.            Methods which return a value cannot be called in this way - their
  1044.            return value must be used. If you don't want to do anything with
  1045.            the return value, the best thing to do is to assign it to some
  1046.            variable.
  1047.  
  1048. 5.16.2:  Expressions
  1049.         Expressions are used in statements. (An attempt to use an expression
  1050.         on its own in place of a statement will usually result in the error
  1051.         message "Statement expected"). An expression may be one of the
  1052.         following:
  1053.  
  1054. 5.16.2.1:   integer
  1055.            An ordinary integer number is an expression of type INT, e.g. 42,
  1056.            5, 367. Commas and decimals points are not allowed i.e. 1000 must
  1057.            be written as 1000 not 1,000 or 1000.0. Negative numbers are
  1058.            allowed e.g. -65, but these are treated as expressions consisting
  1059.            of a minus sign followed by a positive number (see below).
  1060.  
  1061.            There is a limit to how high or low a value numbers in your
  1062.            adventure can have. It depends on the type of computer system you
  1063.            have, and also possibly on the version of OASYS you have. Some
  1064.            types of computer can handle "32-bit" numbers which can range
  1065.            from -2147483648 to 2147483647 i.e. about minus two billion to
  1066.            plus two billion, which should be plenty for most purposes! Other
  1067.            types of computer can handle only "16-bit" numbers which can
  1068.            range from -32768 to 32767 i.e. minus thirty-two thousand to plus
  1069.            thirty-two thousand, which should still be enough in most cases.
  1070.  
  1071.            If it matters then you can find out whether or not your computer
  1072.            can handle 32-bit numbers:
  1073.  
  1074.            A guideline is that versions of OASYS on IBM PC-compatible
  1075.            computers can probably only handle 16-bit numbers whereas those
  1076.            on other types of system can probably handle 32-bit numbers.
  1077.  
  1078.            You can find out for sure by copying EXAMPLE.S and putting
  1079.            something like "PRINT 1000000" into the INIT method. If you get
  1080.            the right answer i.e. 1000000 on the screen, you can use 32-bit
  1081.            numbers, if you get the wrong answer then you can only use 16-bit
  1082.            numbers.
  1083.  
  1084.            While it is possible for different versions of OASYS to differ in
  1085.            their ability to handle 32-bit numbers, if your copy of OASYS can
  1086.            handle 32-bit numbers, it will always be able to do so on any
  1087.            computer on which it will work at all. This is another reason to
  1088.            not necessarily throw away your old version of OASYS if you get a
  1089.            new version (see the section on "Versions").
  1090.  
  1091. 5.16.2.2:   string
  1092.            A string is anything between pairs of double quote marks. The
  1093.            quote marks are not counted as part of the string, e.g. if you
  1094.            have PRINT "HELLO WORLD!" in a method, the following will come up
  1095.            on the screen when the game is run:
  1096.  
  1097.            HELLO WORLD!
  1098.  
  1099.            What if you have a string longer than will fit on one line of
  1100.            your source code e.g. a location description that extends over
  1101.            several lines? There are two ways to do this.
  1102.  
  1103.            First you can just continue the string on the next line e.g.
  1104.  
  1105.            PRINT "You are in a
  1106.            large cavern."
  1107.  
  1108.            The line break between "a" and "large" will be regarded as a
  1109.            space so the display of the string on the player's screen won't
  1110.            be messed up no matter how messy it looks in your source code.
  1111.  
  1112.            Unfortunately even if you have the first line indented as the
  1113.            PRINT statement above is, you must start subsequent lines at the
  1114.            beginning of the line, otherwise the indentation will be regarded
  1115.            as part of the string e.g.
  1116.  
  1117.            PRINT "You are in a
  1118.                large cavern."
  1119.  
  1120.            looks nicer in the source code, but will produce
  1121.  
  1122.            You are in a         large cavern.
  1123.  
  1124.            on the player's screen.
  1125.  
  1126.            You must also be careful not to have any spaces after the "a" on
  1127.            the PRINT statement line, because these are not visible in your
  1128.            source code but will also appear on the player's screen.
  1129.  
  1130.            Second, you can stop the string and start it again. As long as
  1131.            you have nothing else other than spaces, tabs and line breaks
  1132.            between the close quotes and the next open quotes the whole thing
  1133.            is regarded as one string e.g.
  1134.  
  1135.            PRINT "You are in a "
  1136.                "large "
  1137.                "cavern."
  1138.  
  1139.            Here only the stuff inside the quotes is regarded as part of the
  1140.            string so you can indent the subsequent parts, so your source
  1141.            code looks nicer, so this is the method used in ESCAPE.S.
  1142.  
  1143.            However this time you do have to include the spaces between "a"
  1144.            and "large" and between "large" and "cavern" in the quotes.
  1145.  
  1146.            The PRINT statement will cause output to go onto the next line
  1147.            automatically when it reaches the end of the current line so you
  1148.            don't have to worry much about going onto new lines. However you
  1149.            *must* force the output to go onto a new line before the player
  1150.            is asked for the next command otherwise the player will get
  1151.            output like this:
  1152.  
  1153.            You are in a large cavern.>*
  1154.  
  1155.            where the player must type in his next command at the * in the
  1156.            middle of the line. You can avoid this and force the output to go
  1157.            onto a new line like this:
  1158.  
  1159.            PRINT "You are in a large cavern."
  1160.            PRINT "\n"
  1161.  
  1162.            or like this:
  1163.  
  1164.            PRINT "You are in a large cavern.\n"
  1165.  
  1166.            i.e. a "\" (backslash) character followed by the letter N (upper
  1167.            or lower case) will force the output to go onto a new line.
  1168.  
  1169.            Also a "\" character followed by double quotes will cause the
  1170.            double quotes to be put into the string rather than interpreted
  1171.            as the end of the string e.g.
  1172.  
  1173.            PRINT "The giant says \"Fee fie fo fum!\"\n"
  1174.  
  1175.            will produce:
  1176.  
  1177.            The giant says "Fee fie fo fum"!
  1178.  
  1179.            Of course you can avoid the whole problem by just using single
  1180.            quote marks inside strings e.g.
  1181.  
  1182.            PRINT "The giant says 'Fee fie fo fum!'\n"
  1183.  
  1184.            will produce
  1185.  
  1186.            The giant says 'Fee fie fo fum!'
  1187.  
  1188.            which works just as well.
  1189.  
  1190.            [You can put any chacter whatsoever into a string by placing a
  1191.            "\" followed by the ASCII code for the character as a two-digit
  1192.            hexadecimal number e.g. \07 will put a beep into the string. This
  1193.            method must be used to get an actual "\".]
  1194.  
  1195. 5.16.2.3:   expression operator expression
  1196.            The operator may be either an arithmetic, comparison or logical
  1197.            operator.
  1198.  
  1199. 5.16.2.3.1:    Arithmetic operators
  1200.           The arithmetic operators are:
  1201.  
  1202.           +   addition
  1203.           -   subtraction
  1204.           *   multiplication
  1205.           /   division
  1206.           %   remainder after division
  1207.  
  1208.           All take two INT expressions and return an INT expression e.g.
  1209.  
  1210.           4 + 5
  1211.  
  1212.           gives 9,
  1213.  
  1214.           29 / 10
  1215.  
  1216.           gives 2 (in OASYS, division always rounds down) and
  1217.  
  1218.           29 % 10
  1219.  
  1220.           gives 9 (the remainder when 29 is divided by 10).
  1221.  
  1222. 5.16.2.3.2:    Comparison operators
  1223.           The comparison operators compare two things and return a true
  1224.           or false result accordingly. For example
  1225.  
  1226.           A > B
  1227.  
  1228.           returns true if A is greater than B and false otherwise. There
  1229.           is no actual type for true or false in OASYS so integers are
  1230.           used instead. A zero integer means false, a nonzero integer
  1231.           means true. So
  1232.  
  1233.           PRINT A > B
  1234.  
  1235.           will display 1 if A is greater than B and 0 otherwise, and
  1236.  
  1237.           DO
  1238.           {
  1239.               ...
  1240.           }
  1241.           WHILE 1
  1242.  
  1243.           is a standard way to keep repeating something forever (or
  1244.           until a BREAK statement or something similar is executed
  1245.           within the loop).
  1246.  
  1247.           ==  Equals
  1248.           !=  Not equals
  1249.           >   Greater than
  1250.           <   Less than
  1251.           >=  Greater than or equal to
  1252.           <=  Less than or equal to
  1253.  
  1254.           The first two can be used to compare objects and strings as
  1255.           well as integers i.e. you can test whether two strings or two
  1256.           objects are the same or not. The last four can only be used on
  1257.           integers i.e. it doesn't make sense to try to check whether
  1258.           one object or string is greater than or less than another.
  1259.  
  1260.           Why the double equals sign "==" for the operator to test for
  1261.           equality? To distinguish it from the assignment "=" sign. It
  1262.           wasn't practical to have them both the same symbol so
  1263.           something else had to be used for one or other of them. It was
  1264.           decided to reserve the one-character symbol "=" for assignment
  1265.           to save typing on the grounds that assignment is done more
  1266.           often than testing for equality.
  1267.  
  1268.           Two expressions of type OBJECT are regarded as equal only if
  1269.           they actually refer to the *same* object, not just if they
  1270.           refer to objects of the same class or with the same values for
  1271.           all properties.
  1272.  
  1273.           Similarly, two strings are regarded as equal only if they are
  1274.           actually the *same* string, not just if they look identical!
  1275.           e.g.
  1276.  
  1277.           "FRED" == "FRED"
  1278.  
  1279.           returns 0! Whereas given
  1280.  
  1281.           STRING S1
  1282.           STRING S2
  1283.  
  1284.           S1 = "FRED"
  1285.           S2 = S1
  1286.  
  1287.           then
  1288.  
  1289.           S1 == S2
  1290.  
  1291.           returns 1. (In future versions of OASYS, the result may be 1
  1292.           in both cases). For further explanation, see the section on
  1293.           "Efficiency".
  1294.  
  1295.           "A != B" is of course the same as "NOT (A == B)", similarly
  1296.           ">" is the negation of "<=" and "<" is the negation of ">=".
  1297.  
  1298. 5.16.2.3.3:    Logical operators
  1299.           The logical operators in OASYS are OR and AND (also see NOT
  1300.           below). They take true or false values (such as those returned
  1301.           by the comparison operators) and give true or false values
  1302.           accordingly e.g.
  1303.  
  1304.           1 == 2 OR 1 == 1
  1305.  
  1306.           returns 1 whereas
  1307.  
  1308.           1 == 2 AND 1 == 1
  1309.  
  1310.           returns 0 because OR will return 1 if either the expression on
  1311.           the left OR the expression on the right (or both) is true,
  1312.           whereas AND will return 1 only if both the expression on the
  1313.           left AND the one on the right are true.
  1314.  
  1315.           In the second case, the AND operator could have known it was
  1316.           going to return 0 as soon as it evaluated the expression on
  1317.           the left. Hence there was no need for it to evaluate the
  1318.           expression on the right. However the OASYS AND and OR
  1319.           operators are not very intelligent and always evaluate both
  1320.           expressions even when there is no need. This can be important
  1321.           when one expression has "side-effects" i.e. causes things to
  1322.           happen as well as returning a value, such as a method call.
  1323.           See "Recursion" for an example.
  1324.  
  1325. 5.16.2.3.4:    Operator precedence
  1326.           In OASYS just as in mathematics some operators are calculated
  1327.           before others e.g. 1 + 2 * 3 means 1 + (2 * 3) not (1 + 2) *
  1328.           3. The list of operators is shown below in descending order of
  1329.           precedence:
  1330.  
  1331.           * / %
  1332.           + -
  1333.           > < >= <=
  1334.           == !=
  1335.           AND
  1336.           OR
  1337.  
  1338.           The order is designed so that expressions usually work the way
  1339.           you expect them to e.g.
  1340.  
  1341.           A == B AND C == D
  1342.  
  1343.           means
  1344.  
  1345.           (A == B) AND (C == D)
  1346.  
  1347.           rather than
  1348.  
  1349.           A == (B AND C) == D
  1350.  
  1351.           as would be the case if AND had a higher precedence than "==".
  1352.           While legal, the above is probably not what was intended!
  1353.  
  1354.           The unary minus sign and NOT (q.v.) both have higher
  1355.           precedence than any normal operator so -5 * 7 means (-5) * 7
  1356.           rather than -(5 * 7).
  1357.  
  1358. 5.16.2.4:   - expression
  1359.            A minus sign followed by a number gives the negative of the
  1360.            number. This is a special case called "unary minus" and is
  1361.            regarded as quite distinct from the use of the minus sign to
  1362.            denote subtraction.
  1363.  
  1364.            The plus sign cannot be used in the same way i.e. +5 on its own
  1365.            does not mean the same thing as 5, instead it generates an error.
  1366.  
  1367. 5.16.2.5:   NOT expression
  1368.            The word NOT followed by an expression gives zero if the
  1369.            expression is nonzero and 1 if the expression is zero, e.g.
  1370.  
  1371.            NOT 4 == 5
  1372.  
  1373.            gives 1.
  1374.  
  1375. 5.16.2.6:   (expression)
  1376.            Surrounding an expression in brackets cause it to be evaluated
  1377.            first, just like in normal arithmetic e.g.
  1378.  
  1379.            4 + 5 * 2
  1380.  
  1381.            gives 4 + 10 = 14 but
  1382.  
  1383.            (4 + 5) * 2
  1384.  
  1385.            gives 9 * 2 = 18. This also works with non-arithmetic operators
  1386.            e.g.
  1387.  
  1388.            NOT (A == B AND C == D)
  1389.  
  1390.            is different from
  1391.  
  1392.            (NOT A == B) AND (C == D)
  1393.  
  1394. 5.16.2.7:   LOAD
  1395.            LOAD will try to load an old game position recorded with SAVE and
  1396.            will return 1 if the load succeeded and 0 if it failed. The
  1397.            reason it returns a value is that it is commonly desired to do
  1398.            something like:
  1399.  
  1400.            IF LOAD
  1401.            PLAYER DESCRIBE_LOCATION
  1402.  
  1403.            i.e. only if the load succeeded, give the player an immediate
  1404.            reminder of where he was.
  1405.  
  1406.            LOAD will prompt the player for the name of the file which
  1407.            contains the saved game. It will fail if the file cannot be
  1408.            found. It will also fail if the file is not an OASYS saved game
  1409.            at all, since such files contain a special signature which OASYS
  1410.            can recognize. (This signature is different from the signature
  1411.            which identifies OASYS object files). However the LOAD function
  1412.            will not be able to detect if the saved game was saved from a
  1413.            different game. Such cases will produce "unpredictable results"
  1414.            and it will usually be necessary to reset the computer.
  1415.  
  1416.            What happens if you are testing a game, have saved a position,
  1417.            made a slight change to fix a bug and now want to reload that
  1418.            position to continue where you left off? You can do this *only
  1419.            if* you have not:
  1420.  
  1421.            added or removed any global variables
  1422.  
  1423.            added or removed any properties
  1424.  
  1425.            added or removed any classes
  1426.  
  1427.            added or removed any strings
  1428.  
  1429.            This last is the one that generally creates the most problems. A
  1430.            favourite trick when debugging a method when something is going
  1431.            wrong and you're not sure where is to insert statements at
  1432.            various points like PRINT "Reached point A", PRINT "Reached point
  1433.            B" etc. This will make your saved games unusable! A possible
  1434.            alternative is to put in statements like PRINT 1001, PRINT 1002
  1435.            etc. as substitutes.
  1436.  
  1437.            [The signature for an OASYS saved game is the 4-byte C string
  1438.            "oas\1" at the beginning of the file.]
  1439.  
  1440. 5.16.2.8:   RANDOM expression
  1441.            The expression must give an INT result, and RANDOM will return a
  1442.            random number between expression - 1 and 0 inclusive e.g.
  1443.  
  1444.            RANDOM 5
  1445.  
  1446.            will generate a random number somewhere between 0 and 4. RANDOM 1
  1447.            will always generate 0 and RANDOM 0 will give a "Division by
  1448.            zero" error message when the game is run.
  1449.  
  1450.            [The random number generator is seeded from the system clock at
  1451.            the start of every game so you should always get different
  1452.            results.]
  1453.  
  1454. 5.16.2.9:   CREATE class-name
  1455.            This will create an object of the given class and return a
  1456.            reference to it e.g.
  1457.  
  1458.            KITCHEN = CREATE ROOM
  1459.  
  1460.            Why is it said to return a "reference to" the object rather than
  1461.            just the object itself? Well suppose you have:
  1462.  
  1463.            OBJECT SWORD1
  1464.            OBJECT SWORD2
  1465.  
  1466.            SWORD1 = CREATE SWORD
  1467.            SWORD2 = SWORD1
  1468.  
  1469.            Then there is really only one sword but either of the two
  1470.            variables can be used to refer to it.
  1471.  
  1472.            SWORD1 DESC = "A large sword"
  1473.            PRINT SWORD2 DESC
  1474.  
  1475.            will give the result
  1476.  
  1477.            A large sword
  1478.  
  1479.            and
  1480.  
  1481.            DESTROY SWORD1
  1482.            PRINT SWORD2 DESC
  1483.  
  1484.            (here SWORD1 and SWORD2 must be *global* variables otherwise you
  1485.            must add
  1486.  
  1487.            SWORD1 = OBJECT 0
  1488.            SWORD2 = OBJECT 0
  1489.  
  1490.            - see the section on "DESTROY" for the reason.)
  1491.  
  1492.            will give
  1493.  
  1494.            *NULL STRING*
  1495.  
  1496.            because SWORD1 and SWORD2 were the same sword and if SWORD1 no
  1497.            longer exists then of course neither does SWORD2. On the other
  1498.            hand if you had originally put
  1499.  
  1500.            SWORD1 = CREATE SWORD
  1501.            SWORD2 = CREATE SWORD
  1502.  
  1503.            then you would indeed have two different swords.
  1504.  
  1505. 5.16.2.10:  THIS
  1506.            THIS will return a reference to the object to which the current
  1507.            method has been applied. See the earlier section on "THIS" for
  1508.            further details.
  1509.  
  1510. 5.16.2.11:  OBJECT expression
  1511.            All objects in the game at any given time are kept in a big list.
  1512.            OBJECT 1 returns a reference to the first object in this list,
  1513.            OBJECT 2 returns a reference to the second object in the list and
  1514.            so on. The expression can be anything that returns an INT value.
  1515.  
  1516.            Suppose there are currently 200 objects in the game. What happens
  1517.            if you try to evaluate OBJECT 201 or OBJECT -5? You get the "null
  1518.            object". This has been called OBJECT 0 throughout this manual
  1519.            because the expression OBJECT 0 does of course give the null
  1520.            object, but OBJECT -1 would do as well. So would OBJECT 20000
  1521.            unless your game is extremely large!
  1522.  
  1523.            One way to go through every object in the entire system is as
  1524.            follows:
  1525.  
  1526.            INT I
  1527.  
  1528.            I = 1
  1529.            DO
  1530.            {
  1531.            OBJECT I SOME_METHOD
  1532.            I = I + 1
  1533.            }
  1534.            WHILE OBJECT I EXISTS
  1535.  
  1536.            which will start at object 1 and apply SOME_METHOD to every
  1537.            object until it comes to the end of the list. However it's more
  1538.            efficient to use NEXT (q.v.).
  1539.  
  1540.            Objects are added to the end of the list when CREATEd and removed
  1541.            from the list when DESTROYed. The order of the list is always
  1542.            preserved even through a SAVE and LOAD. This means that if you
  1543.            have created object A before object B and you use the above
  1544.            technique (or the equivalent with NEXT) to go through the list,
  1545.            you will always come to A before B.
  1546.  
  1547.            Also if two or more objects are eligible for a command according
  1548.            to the selector methods the first one in the list is selected.
  1549.  
  1550.            This fact is used in ESCAPE.S in the boxes puzzle to ensure that
  1551.            the player is always trying to OPEN the correct box.
  1552.  
  1553. 5.16.2.12:  Local variable
  1554.            The name of a local variable is an expression returning the value
  1555.            of the variable.
  1556.  
  1557. 5.16.2.13:  Method argument
  1558.            Names of method arguments are equivalent to local variables.
  1559.  
  1560. 5.16.2.14:  Global variable
  1561.            The name of a global variable is an expression returning the
  1562.            value of the variable, unless there is a local variable or method
  1563.            argument with the same name (in which case the local variable or
  1564.            argument takes priority).
  1565.  
  1566. 5.16.2.15:  expression property-name
  1567.            The expression must be of type OBJECT. The value of the specified
  1568.            property of the object will be returned. If the expression is
  1569.            OBJECT 0 the value of the property will taken to be in accordance
  1570.            with the rules for uninitialized variables i.e. INT = 0, STRING =
  1571.            "*NULL STRING*" and OBJECT = OBJECT 0.
  1572.  
  1573. 5.16.2.16:  expression EXISTS
  1574.            The expression must give a value of type OBJECT. The EXISTS
  1575.            function will give a value of 1 if the object is not OBJECT 0 and
  1576.            0 if the object is OBJECT 0.
  1577.  
  1578.            expression == OBJECT 0 would do the same job, but less
  1579.            efficiently.
  1580.  
  1581. 5.16.2.17:  expression IS class-name
  1582.            The expression must give a value of type OBJECT. A value of 1
  1583.            will be returned if the object's class is the indicated one, 0
  1584.            otherwise e.g. if you have previously done
  1585.  
  1586.            KITCHEN = CREATE ROOM
  1587.  
  1588.            then
  1589.  
  1590.            KITCHEN IS ROOM
  1591.  
  1592.            will return 1.
  1593.  
  1594. 5.16.2.18:  expression NEXT
  1595.            The expression must give a value of type OBJECT. The next object
  1596.            in the system object list will be returned (see "OBJECT
  1597.            expression" above). When applied to OBJECT 0 or when the object
  1598.            is the last in the list, OBJECT 0 is returned. NEXT can be used
  1599.            to go through all the objects in the game one by one e.g.
  1600.  
  1601.            OBJECT X
  1602.  
  1603.            X = OBJECT 1
  1604.            DO
  1605.            {
  1606.            X SOME_METHOD
  1607.            X = X NEXT
  1608.            }
  1609.            WHILE X EXISTS
  1610.  
  1611.            will apply SOME_METHOD to every object in existence.
  1612.  
  1613. 5.16.2.19:  expression method-name arguments
  1614.            A method which returns a value of INT, STRING or OBJECT can be
  1615.            called in an expression. The syntax is above where the first
  1616.            expression is an object to which the method is to be applied, and
  1617.            the list of arguments must match those expected by the method in
  1618.            number, position and type.
  1619.  
  1620.            The method must return a value, otherwise its call should be a
  1621.            statement and an attempt to use it in an expression will result
  1622.            in the error message "Void type used in expression".
  1623.  
  1624. 5.17: Recursion
  1625.      (This section is not strictly necessary and may be skipped, but the
  1626.      material in it will make some kinds of things easier to do).
  1627.  
  1628.      Since everything must be defined before it is referred to, a method can
  1629.      only call other methods that have been defined before it. But a method
  1630.      can also call itself! This is called "recursion". For example, consider
  1631.      the definition of IS_VISIBLE that says "an object is visible if it is
  1632.      carried by the player, or in the player's location, or if it is inside
  1633.      another object which is both open and visible", e.g. something in a
  1634.      visible open box would also be visible. This can be defined as follows:
  1635.  
  1636.      METHOD INT IS_VISIBLE
  1637.      "That isn't here.\n"
  1638.      {
  1639.          IF THIS IN == PLAYER OR THIS IN == PLAYER IN
  1640.          RETURN 1
  1641.          IF NOT THIS IN EXISTS
  1642.          RETURN 0
  1643.          RETURN THIS IN IS_VISIBLE AND THIS IN IS_OPEN
  1644.      }
  1645.  
  1646.      [Since local variables are allocated on a stack, each re-entry of a
  1647.      method gets its own local variable space.]
  1648.  
  1649.      A recursive definition has been described as "something which is almost
  1650.      but not quite a circular definition". One pitfall of recursion is of
  1651.      accidentally leaving out the "almost but not quite" bit. For example,
  1652.      consider the following:
  1653.  
  1654.      METHOD INT IS_VISIBLE
  1655.      "That isn't here.\n"
  1656.      {
  1657.          RETURN THIS IN == PLAYER OR THIS IN == PLAYER IN OR
  1658.          (THIS IN IS_VISIBLE AND THIS IN IS_OPEN)
  1659.      }
  1660.  
  1661.      At first glance this looks equivalent to the earlier definition.
  1662.      However in this case, even if THIS IN == PLAYER IN and the object is in
  1663.      the player's current location, THIS IN IS_VISIBLE will still be called!
  1664.      (As explained in "Logical Operators", the OASYS OR is not very clever
  1665.      and always evaluates all of its arguments even when this should not be
  1666.      necessary). Similarly when THIS IN IS_VISIBLE is called, it will call
  1667.      METHOD IS_VISIBLE again and so on forever. Well it would be forever but
  1668.      OAI will quickly detect this situation when the game is being run and
  1669.      stop with the message "Stack overflow".
  1670.  
  1671.      Actually the above definition would work because sooner or later THIS
  1672.      would equal OBJECT 0 and METHOD IS_VISIBLE would return immediately
  1673.      without getting a chance to call THIS IN IS_VISIBLE. (Unless of course
  1674.      you had two objects each of which was inside the other!) But in general
  1675.      it's something to watch out for.
  1676.  
  1677. 5.18: Errors
  1678.      The following sections list various kinds of error messages which the
  1679.      OAC and OAI programs may give and their causes. For both programs if
  1680.      you ever see an error message beginning with the words "Assertion
  1681.      failed", this probably indicates a bug in OASYS. In this case, please
  1682.      write down the error message and the circumstances under which it
  1683.      occurred and contact the author.
  1684.  
  1685. 5.18.1:  OAC
  1686.         Three kinds of error messages may be given by the OAC program:
  1687.  
  1688.         Normal error messages are indicated by
  1689.  
  1690.         Error near line xxx: yyy
  1691.  
  1692.         where xxx is the line number in the source file and yyy is a message
  1693.         indicating what the problem is.
  1694.  
  1695.         It frequently happens that OAC does not notice an error until a few
  1696.         lines after it has happened, so the real error may be a few lines
  1697.         before the indicated line number. However it will never be after the
  1698.         indicated line number.
  1699.  
  1700.         When one or more errors are encountered during translation, the
  1701.         translation will proceed as normal right up to the point where the
  1702.         object file has been produced. However, OAI will then delete the
  1703.         object file. The purpose of this is to make sure that an invalid
  1704.         object file is never produced, because then the computer could crash
  1705.         if an attempt was made to run it.
  1706.  
  1707.         Fatal error messages are indicated by
  1708.  
  1709.         Fatal error near line xxx: yyy
  1710.  
  1711.         The difference between normal and fatal errors is that when a fatal
  1712.         error is encountered, OAI doesn't understand what you are trying to
  1713.         do and is not able to continue translating your source code. Hence
  1714.         it will stop immediately and you must fix the problem before trying
  1715.         again. In this case no object file is created and if there was an
  1716.         old object file there it is not affected.
  1717.  
  1718.         Some errors occur when you have no INIT method defined, no strings,
  1719.         no vocabulary or whatever - the OAI program is designed on the
  1720.         assumption that these will be present and hence OAC checks for their
  1721.         presence. If you want to write a throwaway game to test some
  1722.         language feature, you could use a copy of EXAMPLE.S and modify it,
  1723.         as it already has all the minimum requirements to translate and run
  1724.         successfully.
  1725.  
  1726.         Other miscellaneous errors may also occur for events such as OAC
  1727.         being unable to find the source file. These normally involve
  1728.         translation stopping immediately as for a fatal error.
  1729.  
  1730. 5.18.2:  OAI
  1731.         The following error messages may be given by the OAI program when
  1732.         running an adventure:
  1733.  
  1734.         Not an OASYS file
  1735.  
  1736.         This message can only be given when OAI is trying to load the object
  1737.         file. It means that the file you have told it to load is not a valid
  1738.         object file produced by the OAC program.
  1739.  
  1740.         [The marker for an OASYS object file is the 4-byte C string "oas\0"
  1741.         at the beginning of the file.]
  1742.  
  1743.         Division by zero
  1744.  
  1745.         This means that somewhere in your method code an attempt has been
  1746.         made to divide by zero (trying to evaluate RANDOM 0 will have this
  1747.         effect).
  1748.  
  1749.         Stack overflow
  1750.  
  1751.         This means that your method code uses too much space in an area of
  1752.         memory known as the "stack". This is used as a scratchpad when
  1753.         evaluating expressions, and is also used for storing local variables
  1754.         and method arguments. A stack overflow will be produced by a runaway
  1755.         recursion (q.v.), otherwise you will have to reduce the depth of
  1756.         method calls, number of local variables etc. used by your code. Note
  1757.         that only the methods being called at the time of the stack overflow
  1758.         have any effect on the amount of stack space used.
  1759.  
  1760.         [A small amount of space on the hardware stack is used for each
  1761.         method call but local variables etc. are allocated on a separate
  1762.         software stack. It is an overflow of this stack which is indicated
  1763.         by the error message.]
  1764.  
  1765.         Nonexistent object
  1766.  
  1767.         An attempt has been made to DESTROY an object which is OBJECT 0.
  1768.  
  1769. 6: Guidelines
  1770. 6.1:  Writing Adventures
  1771.      The following are guidelines on how to write adventure games with
  1772.      OASYS. You don't have to follow them but you may find them useful.
  1773.  
  1774.      OASYS is designed to be a relatively easy system with which to add
  1775.      stuff in as you go along: you can add new global variables, methods,
  1776.      properties etc. without too much difficulty. (Remember to delete your
  1777.      old saved positions!) However you should have at least a full map drawn
  1778.      before you sit down at the computer.
  1779.  
  1780.      Do things with objects rather than flags whenever possible, e.g. in
  1781.      ESCAPE there is a situation where the player encounters a tiger while
  1782.      walking along a corridor! In an older system this might have been
  1783.      handled by a global variable which recorded whether or not the tiger
  1784.      was still there or had been killed. In OASYS it was handled instead by
  1785.      a special object for the tiger - the object was DESTROYed when the
  1786.      tiger was defeated. This approach lets unusual events be handled easily
  1787.      (e.g. what happens if the player tries to GET TIGER?).
  1788.  
  1789.      Follow the "rule of trap the negatives". Suppose you have the player
  1790.      trying to blow something up with some explosive. You might start off
  1791.      with
  1792.  
  1793.      IF NOT EXPLOSIVE IS_CARRIED
  1794.      {
  1795.          PRINT "You have no explosive!\n"
  1796.          RETURN
  1797.      }
  1798.  
  1799.      and then
  1800.  
  1801.      IF NOT DETONATOR IS_CARRIED
  1802.      {
  1803.          PRINT "You've nothing to set off the explosive with!\n"
  1804.          RETURN
  1805.      }
  1806.  
  1807.      and after a few such checks, we now know that the player can indeed do
  1808.      the deed and we have:
  1809.  
  1810.      PRINT "Boom!\n"
  1811.      DESTROY X
  1812.      DESTROY EXPLOSIVE
  1813.      DESTROY DETONATOR
  1814.  
  1815.      or whatever. The point here is that you start off by trapping the most
  1816.      serious problem or "negative" (IF NOT...), with a message and a RETURN
  1817.      statement. If the method gets past that check you trap the next most
  1818.      serious problem and so on. Eventually if the method gets past all the
  1819.      checks you can assume everything is OK and proceed to carry out the
  1820.      command.
  1821.  
  1822.      Copy extensively from the example adventures and any others you can get
  1823.      your hands on. Don't reinvent the wheel!
  1824.  
  1825.      Follow the conventions for indenting statements within curly brackets,
  1826.      IF statements etc. as used in EXAMPLE.S and ESCAPE.S.
  1827.  
  1828.      If your word processor allows it, set tab stops to only three spaces
  1829.      apart so when there are several levels of indentation in your code you
  1830.      still have a good deal of room left before you hit the right-hand edge
  1831.      of the screen.
  1832.  
  1833.      Back up your source code onto floppy disk, magnetic tape or other
  1834.      medium after every working session. (It is not necessary to back up the
  1835.      object file since you can easily recreate it from the source file).
  1836.  
  1837.      When you get a "bug" or error in your game, which you inevitably will,
  1838.      use the strategy of "divide and conquer" i.e. put in diagnostic PRINT
  1839.      statements to tell you the values of variables etc. at various points
  1840.      in the code. Finding whereabouts things are going wrong is half the
  1841.      battle. (Remember if you put in any PRINT statements with strings,
  1842.      delete your old saved positions!)
  1843.  
  1844.      Put a comment such as //DEBUG beside all the diagnostic statements so
  1845.      when you do find the bug you can use your word processor's search
  1846.      facility to find and remove the diagnostics.
  1847.  
  1848.      Put comments beside any obscure bits of code you write. Even if nobody
  1849.      else ever reads your code you might want to come back to it in a
  1850.      month's time.
  1851.  
  1852.      Before starting to write the Adventure Game To End All Adventure Games,
  1853.      ask yourself will it fit into your computer's memory? There's no point
  1854.      in spending weeks writing half of a huge masterpiece and then having to
  1855.      abandon it because you've run out of memory. Compare your design with
  1856.      the ESCAPE game to get an estimate of relative sizes.
  1857.  
  1858. 6.2:  Efficiency
  1859.      The following are guidelines on how to make your game more efficient in
  1860.      two ways: to use less memory in the computer when running and to run
  1861.      faster. However where efficiency conflicts with ease of writing and
  1862.      debugging the adventure, efficiency usually gets lower priority. An
  1863.      exception sometimes happens when the adventure becomes so big it won't
  1864.      fit into the computer's memory!
  1865.  
  1866.      You can reduce memory usage by either reducing the size of the object
  1867.      file (which must be loaded into memory when the game is run) or by
  1868.      reducing the number of objects created or the number of object
  1869.      properties or global variables (which also take up memory).
  1870.  
  1871.      See your computer's manual for information on how to check the size of
  1872.      the object file, and the amount of free memory available.
  1873.  
  1874.      Since you can't reduce the number of objects without making your game
  1875.      less complex, this is not recommended.
  1876.  
  1877.      Eliminating an object property will reduce memory usage. Eliminating a
  1878.      global variable will not significantly reduce memory usage - properties
  1879.      take up memory for each and every object created, whereas global
  1880.      variables only take up memory once. Local variables do not take up
  1881.      memory in the normal sense, but they take up space on the "stack" (see
  1882.      the "Errors" section) which is also of limited size.
  1883.  
  1884.      Most of the space in the object file is taken up by actual method code
  1885.      and strings to be displayed to the player - these tend to be of roughly
  1886.      equal size. The extra "overhead" information takes up relatively little
  1887.      space.
  1888.  
  1889.      You can reduce the size of the object file by reducing the number and
  1890.      length of your strings. This is a measure of desperation, since it will
  1891.      reduce the quality of your adventure. Where possible, reducing the size
  1892.      of the method code while still having it do the same job is the best
  1893.      course.
  1894.  
  1895.      In the current version of OASYS, it doesn't matter whether two strings
  1896.      are the same or different - each one is still stored separately.
  1897.      However this may change in later versions, so if you have the string
  1898.      "Fred" several times in your code, it would only take up space once.
  1899.      (This also affects comparison of strings - see "Comparison Operators"
  1900.      for further details).
  1901.  
  1902.      The use of comments and the insertion of extra spaces and blank lines
  1903.      in your source code makes no difference whatsoever to the efficiency of
  1904.      the adventure (though they will make the souce code take up more disk
  1905.      space and take slightly longer to translate into object code), because
  1906.      comments etc. are not included in the object file.
  1907.  
  1908.      In general, the use of longer identifiers for things like method and
  1909.      variable names also makes no difference to efficiency for the above
  1910.      reason. However due to a quirk of the OAC program design, names of
  1911.      method arguments are included in the object file. So using shorter
  1912.      names for method arguments will save a small amount of space, as will
  1913.      using the same argument names in different methods - if you have many
  1914.      methods with arguments called FRED, the word FRED is only stored once.
  1915.      (In future versions, method argument names may not be included in the
  1916.      object file).
  1917.  
  1918.      Using THIS is more efficient than using a variable or method argument.
  1919.      Suppose you have a method in which you know beforehand that THIS will
  1920.      be the same as PLAYER. (For example, verb methods in a game which does
  1921.      not allow the player to talk to other objects). Then using THIS instead
  1922.      of PLAYER will make your adventure more efficient.
  1923.  
  1924.      Using IS is more efficient than comparing variables. For example,
  1925.      suppose you have IF THIS == PLAYER in a method. If you have a CLASS
  1926.      PLAYER of which the global variable PLAYER is the only example, you
  1927.      could instead write IF THIS IS PLAYER.
  1928.  
  1929.      When a WHILE loop and a DO...WHILE loop will do the same job (e.g.
  1930.      because you know the condition will always be true the first time round
  1931.      the loop), DO...WHILE is more efficient.
  1932.  
  1933. 7: Versions
  1934.       The version number of each OASYS program is displayed in a one-line
  1935.       message when the program is run. (It should be the same for all versions).
  1936.  
  1937.       This copy of the manual is for version 1.0.
  1938.  
  1939.       It is quite likely that an object file produced with one version of OAC
  1940.       will not run with a later version of OAI. In this case OAI will give the
  1941.       message "Not an OASYS file" when it fails to recognize the object file.
  1942.  
  1943.       It is less likely but still possible that a source file written for one
  1944.       version of OAC will not be accepted by a later version of OAC, in other
  1945.       words that the definition of the language will change.
  1946.  
  1947.       This means that if you get a later version of OASYS you shouldn't throw
  1948.       away your old version until you've checked whether or not the later
  1949.       version accepts your old code.
  1950.